package com.symaster.common.util;

import com.symaster.common.thread.WatchThread;

import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;

/**
 * @author yinmiao
 * @version 2022-05-20 17:08
 */
public class ThreadPool implements Closeable {

    private static final Object NUMBER_LOCK_OBJ = new Object();
    private static Integer NUMBER = 0;
    private static int itemNumber = 0;
    private final LinkedList<Runnable> taskList;
    private boolean close;

    public ThreadPool(int concurrentSize) {
        this.taskList = new LinkedList<>();
        this.close = false;
        for (int i = 0; i < concurrentSize; i++) {
            synchronized (NUMBER_LOCK_OBJ) {
                int poolNumber = NUMBER++;
                ThreadItem threadItem = new ThreadItem(poolNumber, itemNumber++, this);
                threadItem.start();
            }
        }
    }

    public boolean isClose() {
        return close;
    }

    private LinkedList<Runnable> getTaskList() {
        return taskList;
    }

    public void execute(Runnable runnable) {
        synchronized (taskList) {
            taskList.add(runnable);
        }
    }

    @Override
    public void close() throws IOException {
        close = true;
    }

    static class ThreadItem extends WatchThread {
        private final LinkedList<Runnable> taskList;
        private final ThreadPool threadPool;

        public ThreadItem(int poolNumber, int itemNumber, ThreadPool threadPool) throws IllegalArgumentException {
            super(0, String.format("SYThreadPool_%s_%s", poolNumber, itemNumber));
            this.taskList = threadPool.getTaskList();
            this.threadPool = threadPool;
        }

        @Override
        protected void execute() throws Exception {
            if (threadPool.isClose()) {
                stop();
                return;
            }
            if (taskList.size() <= 0) {
                TimeUnit.MILLISECONDS.sleep(2);
                return;
            }
            Runnable remove = taskList.remove(0);
            remove.run();
        }
    }

}
